package client

import (
	"fmt"
	"net"
	"os"
	"sync/atomic"
	"time"
	"tio-proxy-agent/core"
	"tio-proxy-agent/log"
)

type GioClient struct {
	config          core.GioConfig
	ReconnectConfig *core.ReconnectConfig
	*core.ChannelContext
	retryCount int32
}

func NewGioClient(config core.GioConfig, reconnect *core.ReconnectConfig) *GioClient {
	gioClient := new(GioClient)
	gioClient.config = config
	gioClient.ReconnectConfig = reconnect
	gioClient.retryCount = 0
	return gioClient
}

func (gioClient *GioClient) Connect(ip string, port int) {
	ctx := core.NewChannelContext(ip, port, gioClient.config)
	if gioClient.ChannelContext != nil {
		close(gioClient.ChannelContext.NewReceivedByteBuffer)
	}
	gioClient.ChannelContext = ctx

	conn, err := net.Dial("tcp", ctx.BindIp+":"+fmt.Sprintf("%d", ctx.BindPort))
	if err != nil {
		gioClient.reconnect()
	}
	defer func(conn net.Conn) {
		err := conn.Close()
		if err != nil {
			log.SugarLogger.Error("GioClient conn close异常:", err)
			os.Exit(1)
		}
	}(conn)

	gioClient.Set("conn", conn)
	gioClient.config.GetGioListener().OnAfterConnected(ctx)
	ChannelManage["proxy"] = gioClient.ChannelContext

	go func() {
		for {
			byteArray := make([]byte, 20480)
			n, err := conn.Read(byteArray)
			if err != nil {
				gioClient.reconnect()
			}
			gioClient.NewReceivedByteBuffer <- byteArray[:n]
		}
	}()

	defer func() { <-make(chan bool) }()
}

func (gioClient *GioClient) reconnect() {
	if gioClient.ReconnectConfig != nil {
		ctx := gioClient.ChannelContext

		if gioClient.ReconnectConfig.RetryCount >= gioClient.retryCount {
			time.Sleep(time.Duration(gioClient.ReconnectConfig.Interval) * time.Millisecond)
			atomic.AddInt32(&gioClient.retryCount, 1)
			gioClient.Connect(ctx.BindIp, ctx.BindPort)
		}
	}
}
